package cn.zhxu.toys.cipher;

import org.apache.commons.codec.binary.Base64;

import java.nio.charset.StandardCharsets;

/**
 * 简单加密算法
 * @author Troy.Zhou
 */
public class SimpleEncryptor implements Encryptor {

	protected byte[] secret;

	public SimpleEncryptor() {
	}
	
	public SimpleEncryptor(byte[] secret) {
		doInit(secret);
	}

	public SimpleEncryptor(String secret) {
		init(secret);
	}

	@Override
	public void init(String secret) {
		doInit(secret.getBytes(StandardCharsets.UTF_8));
	}

	protected void doInit(byte[] secret) {
		this.secret = Md5Utils.toMd5(secret);
	}
	
	@Override
	public byte[] encrypt(byte[] plainBytes) {
		return doEncrypt(secret, plainBytes);
	}

	@Override
	public byte[] encrypt(byte[] secretBytes, byte[] plainBytes) {	
		secretBytes = Md5Utils.toMd5(secretBytes);
		return doEncrypt(secretBytes, plainBytes);
	}

	@Override
	public String encrypt(String plainText) {
		byte[] bytes = doEncrypt(secret, plainText.getBytes(StandardCharsets.UTF_8));
		return Base64.encodeBase64String(bytes);
	}

	@Override
	public String encrypt(String secretText, String plainText) {	
		byte[] secretBytes = secretText.getBytes(StandardCharsets.UTF_8);
		byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
		byte[] bytes = encrypt(secretBytes, plainBytes);
		return Base64.encodeBase64String(bytes);
	}

	protected byte[] doEncrypt(byte[] secretBytes, byte[] plainBytes) {	
		try {
			byte sumx = 0;
			for (byte b : plainBytes) {
				sumx = (byte) ((sumx + b) % 256);
			}
			byte sumy = 0;
			for (byte b : secretBytes) {
				sumy = (byte) ((sumy + b) % 256);
			}
			int textLength = plainBytes.length;
			byte[] sBytes = new byte[textLength];
			for (int i = 0; i < textLength; i++) {
				int si = i % secretBytes.length;
				sBytes[i] = (byte) ((secretBytes[si] + sumx) % 256);
			}
			byte[] encryptBytes = new byte[textLength + 1];
			encryptBytes[textLength] = (byte) ((sumx + sumy) % 256);
			for (int i = 0; i < textLength; i++) {
				encryptBytes[i] = (byte) ((sBytes[i] + plainBytes[i]) % 256);
			}
			return encryptBytes;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}
